package com.lipy.dubboconsumer.aop;

import com.lipy.dubbocommon.entity.Staff;
import com.lipy.dubboconsumer.tool.RedisUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;
import java.util.Objects;

@Component
@Aspect
public class CacheAop {

    @Resource
    RedisUtils redisUtils;

    @Pointcut("@annotation(com.lipy.dubboconsumer.aop.MyCacheable)")
    public void myCacheAspect(){}

    @Before("myCacheAspect()")
    public void doBefore(){
        System.out.println("CacheAop.doBefore");
    }
    // before -> a
   private static final String prefix_key="staff::";
    @Around("myCacheAspect()")
    public Object around(ProceedingJoinPoint joinpoint) {
        System.out.println("CacheAop.around");
        MethodSignature methodSignature = (MethodSignature)joinpoint.getSignature();;
        String[] parameterNames = methodSignature.getParameterNames();
        Method method = methodSignature.getMethod();
        Object[] args = joinpoint.getArgs();

        MyCacheable myCacheable = method.getDeclaredAnnotation(MyCacheable.class);
        String type = myCacheable.type();

        String annoKey = myCacheable.key();
        if(annoKey == "" ){
            annoKey=myCacheable.value();
        }

        ExpressionParser parser = new SpelExpressionParser();
        Expression expression = parser.parseExpression(annoKey);
        EvaluationContext standardEvaluationContext = new StandardEvaluationContext();
        for (int i = 0; i < parameterNames.length; i++) {
            standardEvaluationContext.setVariable(parameterNames[i],args[i]);
        }
        String cacheKey = expression.getValue(standardEvaluationContext).toString();
        cacheKey = prefix_key + cacheKey;
        if("delete".equals(type) || "update".equals(type)){
            redisUtils.del(cacheKey);
        }
        // key handle
        if (cacheKey == ""){
            return null;
        }
        if("select".equals(type)){
            // get value
            Object o = redisUtils.get(cacheKey);
            if(Objects.nonNull(o)){
                return o;
            }
        }
        Object result = null;
        try {
            result = joinpoint.proceed(); // 使用传入的参数执行
        } catch (Throwable throwable) {
            System.out.println("joinpoint.proceed() throwable "+ throwable.getMessage());
            throwable.printStackTrace();
        }
        if("select".equals(type) || "insert".equals(type)){
            redisUtils.set(cacheKey,result);
        }
//        Object proceed = joinpoint.proceed(args); 使用自定义参数执行
//
//
//        return  proceed;


        return result;

    }
    @After("myCacheAspect()")
    public void after(JoinPoint joinpoint){
        System.out.println("CacheAop.after");
    }
    @AfterReturning("myCacheAspect()")
    public void AfterReturning(JoinPoint joinpoint){
        System.out.println("CacheAop.AfterReturning");
    }
    @AfterThrowing(pointcut = "myCacheAspect()",throwing = "e")
    public void AfterThrowing(JoinPoint joinpoint, Throwable e){
        System.out.println("CacheAop.AfterThrowing");
    }

    public static void main(String[] args) {
    }
}
